package client;

import java.io.IOException;
import java.io.StringReader;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Locale;
import java.util.Scanner;

public class Client
{
    public static boolean isConverged = false;
    public static int rowsCount;
    public static int columnsCount;

    public static void main(String[] args) throws IOException
    {
        if (args.length != 2)
        {
            System.err.println("Usage: java Client <host name> <port number>");
            System.exit(1);
        }
        String hostName = args[0];
        int portNumber = Integer.parseInt(args[1]);

        try (
            Socket socket = new Socket(hostName, portNumber)
        )
        {
            TaskProtocol taskProtocol = new TaskProtocol(socket);

            String serverResponse;
            while ((serverResponse = taskProtocol.readString()) != null)
            {
                System.out.println("Got data from server:\n" + serverResponse);
                Scanner inputScanner = new Scanner(new StringReader(serverResponse));
                inputScanner.useLocale(Locale.ENGLISH);
                float epsilon = inputScanner.nextFloat();
                float [][] matrix = getMatrixFromString(inputScanner);
                float [][] modifiedMatrix = modifyMatrix(matrix, epsilon);
                String clientResponse = matrixToString(modifiedMatrix);
                clientResponse += (isConverged) ? 1 : 0;
                taskProtocol.writeString(clientResponse);
            }
        }
        catch (UnknownHostException e)
        {
            System.err.println("Don't know about host " + hostName);
            System.exit(1);
        }
        catch (IOException e)
        {
            System.err.println("Couldn't get I/O for the connection to " + hostName);
            System.exit(1);
        }
        catch (Exception e)
        {
            e.printStackTrace();
            System.exit(1);
        }
        System.out.println("Press any key to exit");
        System.in.read();
    }

    private static float[][] modifyMatrix(float[][] matrix, float epsilon)
    {
        isConverged = true;
        for (int i = 1; i < (rowsCount - 1); i++)
        {
            for (int j = 1; j < (columnsCount - 1); j++)
            {
                float value = (matrix[i - 1][j] + matrix[i + 1][j] + matrix[i][j - 1] + matrix[i][j + 1]) / 4;
                if (Math.abs(value - matrix[i][j]) > epsilon)
                {
                    isConverged = false;
                    matrix[i][j] = value;
                }
            }
        }
        return matrix;
    }


    private static String matrixToString(float[][] matrix)
    {
        String matrixString = "";
        for (int i = 0; i < rowsCount; i++)
        {
            for (int j = 0; j < columnsCount; j++)
            {
                matrixString += matrix[i][j];
                if (j != columnsCount - 1)
                {
                    matrixString += ' ';
                }
            }
            matrixString += '\n';
        }
        return matrixString;
    }

    private static float[][] getMatrixFromString(Scanner inputScanner)
        throws IOException
    {
        rowsCount = inputScanner.nextInt();
        columnsCount = inputScanner.nextInt();
        float[][] matrix = new float[rowsCount][columnsCount];
        for (int i = 0; i < rowsCount; i++)
        {
            for (int j = 0; j < columnsCount; j++)
            {
                matrix[i][j] = inputScanner.nextFloat();
            }
        }
        return matrix;
    }
}